/**************************************************************************************** 
 Copyright © 2003-2012 hbasesoft Corporation. All rights reserved. Reproduction or       <br>
 transmission in whole or in part, in any form or by any means, electronic, mechanical <br>
 or otherwise, is prohibited without the prior written consent of the copyright owner. <br>
 ****************************************************************************************/
package com.hbasesoft.hamibot.task;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import com.hbasesoft.framework.common.GlobalConstants;
import com.hbasesoft.framework.common.utils.date.DateUtil;
import com.hbasesoft.framework.common.utils.logger.LoggerUtil;
import com.hbasesoft.hamibot.Cmd;
import com.hbasesoft.hamibot.entity.AppEntity;
import com.hbasesoft.hamibot.entity.TaskEntity;
import com.hbasesoft.hamibot.vo.AppCmdReqVo;
import com.hbasesoft.hamibot.vo.AppVo;
import com.hbasesoft.hamibot.vo.CmdRespVo;
import com.hbasesoft.hamibot.vo.ConditionCmdVo;
import com.hbasesoft.hamibot.vo.PageKeywordVo;
import com.hbasesoft.hamibot.vo.PageVo;
import com.hbasesoft.hamibot.vo.TaskRespVo;
import com.hbasesoft.hamibot.vo.TaskVo;

/**
 * <Description> <br>
 * 
 * @author 王伟<br>
 * @version 1.0<br>
 * @taskId <br>
 * @CreateDate 2024年12月23日 <br>
 * @since V1.0<br>
 * @see com.hbasesoft.hamibot.task <br>
 */
@Component
public class AutoTaskHandler {

    /** */
    private Random random = new Random();

    /**
     * Description: 执行命令<br>
     * 
     * @author 王伟<br>
     * @taskId <br>
     * @param config
     * @param appEntity
     * @param completeList
     * @param entities
     * @param req
     * @return <br>
     */
    public TaskRespVo execute(final AppVo config, final AppEntity appEntity, final List<TaskEntity> entities,
        final AppCmdReqVo req) {
        TaskRespVo vo = new TaskRespVo();
        AppEntity newApp = appEntity;
        if (newApp == null) {
            newApp = new AppEntity();
            newApp.setApp(req.getAppName());
            newApp.setDeviceId(req.getDeviceId());
            newApp.setCreateBy("");
            newApp.setCreateTime(DateUtil.getCurrentDate());
            newApp.setIsDelete(0);
            newApp.setState((config.getExecTimes() == null ? 1 : config.getExecTimes()) - 1);
            newApp.setUpdateBy(newApp.getCreateBy());
            newApp.setUpdateTime(newApp.getCreateTime());
        }
        vo.setAppEntity(newApp);
        if (newApp.getState() == 1 || ArrayUtils.isNotEmpty(config.getEndRange()) && config.getEndRange().length == 2
            && (System.currentTimeMillis() - newApp.getCreateTime().getTime()) / GlobalConstants.SECONDS
                / GlobalConstants.MINUTES > random.nextInt(config.getEndRange()[0], config.getEndRange()[1])) {
            LoggerUtil.error("当前app任务已经结束了");
            vo.setAppComplete(true);
            return vo;
        }

        if (CollectionUtils.isEmpty(config.getTasks())) {
            LoggerUtil.error("未配置任务，直接结束");
            vo.setAppComplete(true);
            return vo;
        }

        Map<String, TaskVo> taskConfigMap = config.getTasks().stream()
            .collect(Collectors.toMap(t -> t.getName(), t -> t));
        Map<String, TaskEntity> taskEntityMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(entities)) {
            int size = 0;
            for (TaskEntity entity : entities) {
                entity.setFlowState(null);
                taskEntityMap.put(entity.getTask(), entity);
                if (entity.getState() == 1) {
                    size++;
                }
                else {
                    TaskVo taskConfig = taskConfigMap.get(entity.getTask());
                    if (taskConfig != null) {
                        if (taskConfig.getType() == 0) {
                            if (ArrayUtils.isNotEmpty(taskConfig.getTimeRange())
                                && taskConfig.getTimeRange().length == 2
                                && (System.currentTimeMillis() - entity.getCreateTime().getTime())
                                    / GlobalConstants.SECONDS / GlobalConstants.MINUTES > random
                                        .nextInt(taskConfig.getTimeRange()[0], taskConfig.getTimeRange()[1])) {
                                entity.setState(1);
                                entity.setFlowState("任务完成");
                                size++;
                            }
                        }
                        else {
                            int times = StringUtils.isNotEmpty(entity.getContent())
                                ? Integer.parseInt(entity.getContent())
                                : 0;
                            entity.setTimes(times);
                            if (times > taskConfig.getTimes()) {
                                entity.setState(1);
                                entity.setFlowState("任务完成");
                                size++;
                            }
                        }

                    }
                }
            }
            if (config.getTasks().size() - size == 0) {
                LoggerUtil.error("所有任务已执行完毕");
                vo.setAppComplete(true);
                return vo;
            }
        }

        CmdRespVo[] cmds = execute(config, appEntity, taskConfigMap, taskEntityMap, req);
        vo.setCmds(cmds);
        vo.setEntities(taskEntityMap.values());
        return vo;
    }

    private CmdRespVo[] execute(final AppVo config, final AppEntity appEntity, final Map<String, TaskVo> taskConfigMap,
        final Map<String, TaskEntity> taskEntityMap, final AppCmdReqVo req) {
        if (StringUtils.isEmpty(req.getTaskId()) && StringUtils.isEmpty(req.getPage())) {
            CmdRespVo cmd = new CmdRespVo();
            cmd.setCode(Cmd.CHECK_KEYWORDS.getCode());
            cmd.setPageKeywords(getKeywords(req.getPage(), config, taskEntityMap, "检测处理"));
            cmd.setAppName(req.getAppName());
            cmd.setTaskId("检测处理");
            return new CmdRespVo[] {
                cmd
            };
        }
        if (StringUtils.isNotEmpty(req.getPage())) {
            Optional<PageVo> taskOp = config.getPages().stream().filter(p -> req.getPage().equals(p.getName()))
                .findFirst();
            if (taskOp.isPresent()) {
                PageVo taskVo = taskOp.get();

                ConditionCmdVo condition = taskVo.getConditions().stream().filter(c -> {
                    boolean result = true;

                    TaskEntity taskEntity = null;
                    if (StringUtils.isNotEmpty(c.getTask())) {
                        taskEntity = taskEntityMap.get(c.getTask());
                        if (taskEntity == null) {
                            taskEntity = new TaskEntity();
                            taskEntity.setApp(req.getAppName());
                            taskEntity.setDeviceId(req.getDeviceId());
                            taskEntity.setState(0);
                            taskEntity.setTask(c.getTask());
                            taskEntity.setCreateTime(DateUtil.getCurrentDate());
                            taskEntity.setUpdateTime(taskEntity.getCreateTime());
                            taskEntityMap.put(c.getTask(), taskEntity);
                        }
                        else {
                            result = result && taskEntity.getState() != 1;
                        }

                        // 匹配创建时间范围
                        if (result && ArrayUtils.isNotEmpty(c.getCreateTimeRange())
                            && c.getCreateTimeRange().length == 2) {
                            result = result && (System.currentTimeMillis() - taskEntity.getCreateTime().getTime())
                                / GlobalConstants.SECONDS > random.nextInt(c.getCreateTimeRange()[0],
                                    c.getCreateTimeRange()[1]);
                        }
                    }

                    if (result && CollectionUtils.isNotEmpty(c.getKeywords())) {
                        result = result && matchKeyword(c.getKeywords(), req.getKeywords());
                    }

                    // 匹配流程状态
                    if (result && CollectionUtils.isNotEmpty(c.getStateRange())) {
                        result = result && c.getStateRange().contains(req.getTaskId());
                    }

                    // 匹配更新时间范围
                    if (result && ArrayUtils.isNotEmpty(c.getUpdateTimeRange()) && c.getUpdateTimeRange().length == 2) {
                        result = result && (System.currentTimeMillis() - appEntity.getUpdateTime().getTime())
                            / GlobalConstants.SECONDS > random.nextInt(c.getUpdateTimeRange()[0],
                                c.getUpdateTimeRange()[1]);
                    }

                    return result;
                }).findFirst().get();

                if (condition != null) {

                    // 如果任务已经执行了
                    if (StringUtils.isNotEmpty(condition.getTask())) {
                        TaskEntity taskEntity = taskEntityMap.get(condition.getTask());
                        if (taskEntity != null && StringUtils.isEmpty(taskEntity.getFlowState())
                            && taskEntity.getId() == null) {
                            taskEntity.setFlowState("开始任务");
                        }
                    }

                    // 处理任务完成
                    if (StringUtils.isNotEmpty(condition.getEndTask())) {
                        TaskVo cfg = taskConfigMap.get(condition.getEndTask());
                        if (cfg != null) {
                            TaskEntity taskEntity = taskEntityMap.get(condition.getEndTask());
                            if (taskEntity == null) {
                                taskEntity = new TaskEntity();
                                taskEntity.setApp(req.getAppName());
                                taskEntity.setDeviceId(req.getDeviceId());
                                taskEntity.setState(0);
                                taskEntity.setTask(condition.getEndTask());
                                taskEntity.setTimes(0);
                                taskEntity.setCreateTime(DateUtil.getCurrentDate());
                                taskEntity.setUpdateTime(taskEntity.getCreateTime());
                                taskEntityMap.put(condition.getEndTask(), taskEntity);
                            }
                            if (cfg.getType() == 0) {
                                taskEntity.setFlowState("任务完成");
                                taskEntity.setState(1);
                            }
                            else {
                                taskEntity.setTimes(taskEntity.getTimes() + 1);
                                taskEntity.setContent(taskEntity.getTimes() + "");
                                taskEntity.setFlowState("任务完成" + taskEntity.getContent());
                            }
                        }
                    }

                    LoggerUtil.info("目前处于》{0}页面", taskVo.getName());

                    String conditionState = StringUtils.replace(condition.getState(), "${state}", req.getTaskId());

                    List<PageKeywordVo> keywords = getKeywords(req.getPage(), config, taskEntityMap, conditionState);
                    condition.getCmds().forEach(t -> {
                        t.setPage(taskVo.getName());
                        t.setPageKeywords(keywords);
                        t.setTaskId(conditionState);
                        t.setAppName(req.getAppName());
                    });
                    return condition.getCmds().toArray(new CmdRespVo[0]);
                }
                return null;

            }
        }

        LoggerUtil.info("目前处于》未知页面");
        CmdRespVo cmd = new CmdRespVo();
        cmd.setUnmatch(config.getUnmatch());
        cmd.setCode(Cmd.RETURN_BACK.getCode());
        cmd.setPageKeywords(getKeywords(req.getPage(), config, taskEntityMap, req.getTaskId()));
        cmd.setTaskId(req.getTaskId());
        cmd.setAppName(req.getAppName());
        cmd.setPage("未知页面");
        return new CmdRespVo[] {
            cmd
        };

    }

    private boolean matchKeyword(final List<String> keywords, final List<String> list) {
        if (CollectionUtils.isEmpty(list)) {
            return false;
        }
        for (String keyword : keywords) {
            if (!list.contains(keyword)) {
                return false;
            }
        }
        return true;
    }

    private List<PageKeywordVo> getKeywords(final String page, final AppVo config,
        final Map<String, TaskEntity> taskEntityMap, final String nextState) {
        List<PageKeywordVo> keywords = new ArrayList<>();
        config.getPages().forEach(t -> {
            PageKeywordVo vo = new PageKeywordVo();
            keywords.add(vo);
            vo.setName(t.getName());
            vo.setKeywords(t.getKeywords());
            if (CollectionUtils.isNotEmpty(t.getConditions())) {
                List<String> kws = new ArrayList<String>();
                t.getConditions().forEach(c -> {
                    boolean flag = true;
                    if (StringUtils.isNotEmpty(c.getTask())) {
                        TaskEntity taskEntity = taskEntityMap.get(c.getTask());
                        if (taskEntity != null && taskEntity.getState() == 1) {
                            flag = false;
                        }
                    }

                    if (flag && StringUtils.isNotEmpty(page) && page.equals(t.getName())
                        && StringUtils.isNotEmpty(nextState) && CollectionUtils.isNotEmpty(c.getStateRange())
                        && !c.getStateRange().contains(nextState)) {
                        flag = false;
                    }

                    if (flag && CollectionUtils.isNotEmpty(c.getKeywords())) {
                        for (String k : c.getKeywords()) {
                            if (!kws.contains(k)) {
                                kws.add(k);
                            }
                        }
                    }
                });
                if (CollectionUtils.isNotEmpty(kws)) {
                    vo.setConditionKeywords(kws);
                }
            }
        });
        if (StringUtils.isNotEmpty(page)) {
            Collections.sort(keywords, (k1, k2) -> {
                return page.equals(k1.getName()) ? -1 : 1;
            });
        }
        return keywords;
    }

}
